home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Linux Cubed Series 2: Applications
/
Linux Cubed Series 2 - Applications.iso
/
circuits
/
pcb-1.000
/
pcb-1
/
pcb-1.3
/
draw.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-02-27
|
19KB
|
650 lines
/*
* COPYRIGHT
*
* PCB, interactive printed circuit board design
* Copyright (C) 1994,1995 Thomas Nau
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* Contact addresses for paper mail and Email:
* Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany
* Thomas.Nau@rz.uni-ulm.de
*
*/
static char *rcsid = "$Header: /sda6/users/nau/src/pcb/RCS/draw.c,v 2.2 1994/10/03 16:00:05 nau Exp $";
/* drawing routines
*/
/* ---------------------------------------------------------------------------
* define TO_SCREEN before macro.h is included from global.h
*/
#define TO_SCREEN(a) ((a) >> ZoomValue)
#include "global.h"
#include "crosshair.h"
#include "data.h"
#include "draw.h"
#include "mymem.h"
#include "misc.h"
#include "rotate.h"
#include "select.h"
/* ---------------------------------------------------------------------------
* some local constants
*/
#define TAN_CONST 0.207106781 /* 0.5*tan(22.5) */
/* ---------------------------------------------------------------------------
* some local types
*/
typedef struct
{
float X,
Y;
} FloatPolyType, *FloatPolyTypePtr;
/* ---------------------------------------------------------------------------
* some local identifiers
*/
static int ZoomValue; /* zoom and drawable common to */
static Window DrawingWindow; /* all drawing routines */
static XPoint Outline[MAX_SIZE+1][8];
/* ---------------------------------------------------------------------------
* some local prototypes
*/
static void Redraw(Boolean);
static void DrawEverything(void);
static void DrawLayer(LayerTypePtr);
static void InitSpecialPolygon(void);
static void DrawSpecialPolygon(GC, Position, Position, XPoint *);
static void DrawPinOrViaLowLevel(PinTypePtr);
static void DrawLineLowLevel(LineTypePtr);
static void DrawBoxLowLevel(BoxTypePtr);
static void DrawTextLowLevel(TextTypePtr);
static void DrawPolygonLowLevel(PolygonTypePtr);
static void DrawArcLowLevel(ArcTypePtr);
static void DrawElementPackageLowLevel(ElementTypePtr Element);
/* ---------------------------------------------------------------------------
* redraws the output area without clearing it
*/
void RedrawOutput(void)
{
Redraw(False);
}
/* ---------------------------------------------------------------------------
* redraws the output area after clearing it
*/
void ClearAndRedrawOutput(void)
{
Redraw(True);
}
/* ----------------------------------------------------------------------
* redraws all the data
* all necessary sizes are already set by the viewport widget and
* by the event handlers
*/
static void Redraw(Boolean ClearWindow)
{
XEvent event;
/* check if window already exists */
if (Output.OutputWindow)
{
/* remove all other pending expose events from queue */
while (XtAppPending(Context))
{
XtAppNextEvent(Context, &event);
if (event.type != Expose ||
((XExposeEvent *) &event)->window != Output.OutputWindow)
XtDispatchEvent(&event);
}
/* switch off crosshair, change drawing window and redraw
* everything
*/
HideCrosshair(True);
SwitchDrawingWindow(PCB->Zoom, Output.OutputWindow);
/* reset the cursor state because of clearing the background
* of the drawing area
*/
if (ClearWindow)
{
XSetForeground(Dpy, Output.fgGC, Settings.OffLimitColor);
XFillRectangle(Dpy, DrawingWindow, Output.fgGC,
0, 0, MAX_COORD, MAX_COORD);
XFillRectangle(Dpy, DrawingWindow, Output.bgGC,
0, 0, TO_SCREEN(PCB->MaxWidth), TO_SCREEN(PCB->MaxHeight));
Crosshair.On = False;
}
DrawEverything();
/* redraw might have come from scrolling the window
* so we do an update of the cursor position
*/
MoveCrosshairRelative(0, 0);
RestoreCrosshair(True);
}
}
/* ----------------------------------------------------------------------
* setup of zoom and output window for the next drawing operations
*/
void SwitchDrawingWindow(int Zoom, Window OutputWindow)
{
ZoomValue = Zoom;
DrawingWindow = OutputWindow;
InitSpecialPolygon();
}
/* ---------------------------------------------------------------------------
* initializes some identifiers for a new zoom factor and redraws whole screen
*/
static void DrawEverything(void)
{
Cardinal i;
/* draw all layers beside the current one */
for (i = MAX_LAYER-1; i; i--)
if ((LAYER_ON_STACK(i))->On)
DrawLayer(LAYER_ON_STACK(i));
/* draw element packages; pins are drawn by RedrawCurrentLayer() */
if (PCB->ElementOn)
ELEMENT_LOOP(PCB->Data,
DrawElementPackage(element);
DrawElementName(element);
);
/* make sure that the current layer is always visible */
RedrawCurrentLayer();
if (Settings.DrawGrid)
DrawGrid();
}
/* ---------------------------------------------------------------------------
* redraws the current layer as well as pins and vias
* the later ones are drawn at last to make the drilling hole visible
*/
void RedrawCurrentLayer(void)
{
HideCrosshair(True);
DrawLayer(CURRENT);
/* draw element pins */
if (PCB->PinOn)
ELEMENT_LOOP(PCB->Data, DrawElementPins(element););
/* draw vias */
if (PCB->ViaOn)
VIA_LOOP(PCB->Data, DrawVia(via););
RestoreCrosshair(True);
}
/* ---------------------------------------------------------------------------
* draws one layer
*/
static void DrawLayer(LayerTypePtr Layer)
{
/* draw all objects by calling their drawing routines */
LINE_LOOP(Layer, DrawLine(Layer, line););
TEXT_LOOP(Layer, DrawText(Layer, text););
POLYGON_LOOP(Layer, DrawPolygon(Layer, polygon););
}
/* ---------------------------------------------------------------------------
* initializes some zoom dependend information for pins and lines
* just to speed up drawing a bit
*/
static void InitSpecialPolygon(void)
{
int i, j;
static FloatPolyType p[8] = {{ 0.5, -TAN_CONST},
{ TAN_CONST, -0.5},
{-TAN_CONST, -0.5},
{ -0.5, -TAN_CONST},
{ -0.5, TAN_CONST},
{-TAN_CONST, 0.5},
{ TAN_CONST, 0.5},
{ 0.5, TAN_CONST}};
/* loop over maximum number of different sizes */
for (i = 0; i <= MAX(MAX_PINORVIASIZE, MAX_LINESIZE); i++)
for (j = 0; j < 8; j++)
{
Outline[i][j].x = (p[j].X * TO_SCREEN_X(i));
Outline[i][j].y = (p[j].Y * TO_SCREEN_Y(i));
}
}
/* ---------------------------------------------------------------------------
* draws one polygon
* x and y are already in display coordinates
* the points are numbered:
*
* 5 --- 6
* / \
* 4 7
* | |
* 3 0
* \ /
* 2 --- 1
*
*/
static void DrawSpecialPolygon(GC DrawGC,
Position X, Position Y, XPoint *PolyPtr)
{
int i;
XPoint polygon[8];
/* add line offset */
for (i = 0; i < 8; i++)
{
polygon[i].x = X+ PolyPtr[i].x;
polygon[i].y = Y+ PolyPtr[i].y;
}
XFillPolygon(Dpy, DrawingWindow, DrawGC,
polygon, ENTRIES(polygon), Convex, CoordModeOrigin);
}
/* ---------------------------------------------------------------------------
* lowlevel drawing routine for pins and vias
*/
static void DrawPinOrViaLowLevel(PinTypePtr Ptr)
{
/* transform X11 specific coord system */
DrawSpecialPolygon(Output.fgGC, TO_SCREEN_X(Ptr->X), TO_SCREEN_Y(Ptr->Y),
&Outline[Ptr->Thickness][0]);
DrawSpecialPolygon(Output.bgGC, TO_SCREEN_X(Ptr->X), TO_SCREEN_Y(Ptr->Y),
&Outline[Ptr->DrillingHole][0]);
}
/* ---------------------------------------------------------------------------
* lowlevel drawing routine for lines
*/
static void DrawLineLowLevel(LineTypePtr Line)
{
XSetLineAttributes(Dpy, Output.fgGC,
TO_SCREEN(Line->Thickness),
LineSolid, CapRound, JoinRound);
XDrawLine(Dpy, DrawingWindow, Output.fgGC,
TO_SCREEN_X(Line->X1), TO_SCREEN_Y(Line->Y1),
TO_SCREEN_X(Line->X2), TO_SCREEN_Y(Line->Y2));
}
/* ---------------------------------------------------------------------------
* lowlevel drawing routines for boxes
*/
static void DrawBoxLowLevel(BoxTypePtr Box)
{
Position x, y;
Dimension width, height;
/* convert x and y to window coordinates */
x = TO_SCREEN_X(Box->X1);
y = TO_SCREEN_Y(Box->Y1);
width = TO_SCREEN(Box->X2 -Box->X1);
height = TO_SCREEN(Box->Y2 -Box->Y1);
XFillRectangle(Dpy, DrawingWindow, Output.fgGC, x, y, width, height);
}
/* ---------------------------------------------------------------------------
* lowlevel drawing routine for text objects
*/
static void DrawTextLowLevel(TextTypePtr Text)
{
Position x = Text->X,
y = Text->Y,
x0 = 0; /* initialize to get rid of warnings */
unsigned char *string = (unsigned char *) Text->TextString;
Cardinal n;
FontTypePtr font = &PCB->Font;
/* if text has to be mirrored, get x0 with the unrotated
* width of the surrounding box (which is the length of the string)
*/
if (TEST_FLAG(MIRRORFLAG, Text))
{
Dimension width = Text->BoundingBox.X2 -Text->BoundingBox.X1,
height = Text->BoundingBox.Y2 -Text->BoundingBox.Y1;
if (Text->Direction == 0 || Text->Direction == 2)
x0 = Text->X +width/2;
else
x0 = Text->X +height/2;
}
while (string && *string)
{
/* draw lines if symbol is valid and data is present */
if (*string <= MAX_FONTPOSITION && font->Symbol[*string].Valid)
{
LineTypePtr line = font->Symbol[*string].Line;
LineType newline;
for (n = font->Symbol[*string].LineN; n; n--, line++)
{
/* create one line, scale and move it */
newline = *line;
newline.X1 = newline.X1 *Text->Scale /100 +x;
newline.Y1 = newline.Y1 *Text->Scale /100 +y;
newline.X2 = newline.X2 *Text->Scale /100 +x;
newline.Y2 = newline.Y2 *Text->Scale /100 +y;
newline.Thickness = newline.Thickness *Text->Scale /100;
/* do some mirroring and rotations */
if (TEST_FLAG(MIRRORFLAG, Text))
{
newline.X1 = 2*x0 -newline.X1;
newline.X2 = 2*x0 -newline.X2;
}
RotateLineLowLevel(&newline,Text->X,Text->Y,Text->Direction);
DrawLineLowLevel(&newline);
}
/* move on to next cursor position */
x += ((font->Symbol[*string].Width +font->Symbol[*string].Delta)
*Text->Scale /100);
}
else
{
/* the default symbol is a filled box */
BoxType defaultsymbol = PCB->Font.DefaultSymbol;
defaultsymbol.X1 = defaultsymbol.X1 *Text->Scale /100 +x;
defaultsymbol.Y1 = defaultsymbol.Y1 *Text->Scale /100 +y;
/* do some mirroring and rotations */
if (TEST_FLAG(MIRRORFLAG, Text))
defaultsymbol.X1 = 2*x0 -defaultsymbol.X1 -defaultsymbol.X2;
RotateBoxLowLevel(&defaultsymbol,Text->X,Text->Y, Text->Direction);
DrawBoxLowLevel(&defaultsymbol);
/* move on to next cursor position */
x += ((defaultsymbol.X2 -defaultsymbol.X1)/4 *Text->Scale /100);
}
string++;
}
}
/* ---------------------------------------------------------------------------
* lowlevel drawing routine for polygons
*/
static void DrawPolygonLowLevel(PolygonTypePtr Polygon)
{
static XPoint *data = NULL; /* tmp pointer */
static Cardinal max = 0;
/* allocate memory for data with screen coordinates */
if (Polygon->PointN > max)
{
max = Polygon->PointN;
data = (XPoint *) MyRealloc(data, max *sizeof(XPoint),
"DrawPolygonLowLevel()");
}
/* copy data to tmp array and convert it to screen coordinates */
POLYGONPOINT_LOOP(Polygon,
data[n].x = TO_SCREEN_X(point->X);
data[n].y = TO_SCREEN_Y(point->Y);
);
XFillPolygon(Dpy, DrawingWindow, Output.fgGC,
data, Polygon->PointN, Complex, CoordModeOrigin);
}
/* ---------------------------------------------------------------------------
* lowlevel routine to element arcs
*/
static void DrawArcLowLevel(ArcTypePtr Arc)
{
/* angles have to be converted to X11 notation */
XSetLineAttributes(Dpy, Output.fgGC,
TO_SCREEN(Arc->Thickness), LineSolid, CapRound, JoinRound);
XDrawArc(Dpy, DrawingWindow, Output.fgGC,
TO_SCREEN_X(Arc->X -Arc->Width), TO_SCREEN_Y(Arc->Y -Arc->Height),
TO_SCREEN(2*Arc->Width), TO_SCREEN(2*Arc->Height),
(Arc->StartAngle +180) *64, Arc->Delta *64);
}
/* ---------------------------------------------------------------------------
* draws the package of an element
*/
static void DrawElementPackageLowLevel(ElementTypePtr Element)
{
/* draw lines, arcs, text and pins */
ELEMENTLINE_LOOP(Element, DrawLineLowLevel(line););
ARC_LOOP(Element, DrawArcLowLevel(arc););
}
/* ---------------------------------------------------------------------------
* draw a via object
*/
void DrawVia(PinTypePtr Via)
{
if (TEST_FLAG(SELECTEDFLAG, Via))
XSetForeground(Dpy, Output.fgGC, PCB->SelectedColor);
else
if (TEST_FLAG(FOUNDFLAG, Via))
XSetForeground(Dpy, Output.fgGC, PCB->ConnectedColor);
else
XSetForeground(Dpy, Output.fgGC, PCB->ViaColor);
DrawPinOrViaLowLevel(Via);
}
/* ---------------------------------------------------------------------------
* draw a pin object
*/
void DrawPin(PinTypePtr Pin)
{
if (TEST_FLAG(SELECTEDFLAG, Pin))
XSetForeground(Dpy, Output.fgGC, PCB->SelectedColor);
else
if (TEST_FLAG(FOUNDFLAG, Pin))
XSetForeground(Dpy, Output.fgGC, PCB->ConnectedColor);
else
XSetForeground(Dpy, Output.fgGC, PCB->PinColor);
DrawPinOrViaLowLevel(Pin);
}
/* ---------------------------------------------------------------------------
* draws a line on a layer
*/
void DrawLine(LayerTypePtr Layer, LineTypePtr Line)
{
if (TEST_FLAG(SELECTEDFLAG, Line))
XSetForeground(Dpy, Output.fgGC, PCB->SelectedColor);
else
if (TEST_FLAG(FOUNDFLAG, Line))
XSetForeground(Dpy, Output.fgGC, PCB->ConnectedColor);
else
XSetForeground(Dpy, Output.fgGC, Layer->Color);
DrawLineLowLevel(Line);
}
/* ---------------------------------------------------------------------------
* draws a text on a layer
*/
void DrawText(LayerTypePtr Layer, TextTypePtr Text)
{
if (TEST_FLAG(SELECTEDFLAG, Text))
XSetForeground(Dpy, Output.fgGC, PCB->SelectedColor);
else
XSetForeground(Dpy, Output.fgGC, Layer->Color);
DrawTextLowLevel(Text);
}
/* ---------------------------------------------------------------------------
* draws a polygon on a layer
*/
void DrawPolygon(LayerTypePtr Layer, PolygonTypePtr Polygon)
{
if (TEST_FLAG(SELECTEDFLAG, Polygon))
XSetForeground(Dpy, Output.fgGC, PCB->SelectedColor);
else
if (TEST_FLAG(FOUNDFLAG, Polygon))
XSetForeground(Dpy, Output.fgGC, PCB->ConnectedColor);
else
XSetForeground(Dpy, Output.fgGC, Layer->Color);
DrawPolygonLowLevel(Polygon);
}
/* ---------------------------------------------------------------------------
* draws an element
*/
void DrawElement(ElementTypePtr Element)
{
/* set color and draw lines, arcs, text and pins */
if (TEST_FLAG(SELECTEDFLAG, Element))
XSetForeground(Dpy, Output.fgGC, PCB->SelectedColor);
else
XSetForeground(Dpy, Output.fgGC, PCB->ElementColor);
DrawElementPackageLowLevel(Element);
DrawElementName(Element);
DrawElementPins(Element);
}
/* ---------------------------------------------------------------------------
* draws the name of an element
*/
void DrawElementName(ElementTypePtr Element)
{
if (TEST_FLAG(SELECTEDFLAG, &ELEMENT_TEXT(PCB, Element)))
XSetForeground(Dpy, Output.fgGC, PCB->SelectedColor);
else
XSetForeground(Dpy, Output.fgGC, PCB->ElementColor);
DrawTextLowLevel(&ELEMENT_TEXT(PCB, Element));
}
/* ---------------------------------------------------------------------------
* draws the package of an element
*/
void DrawElementPackage(ElementTypePtr Element)
{
/* set color and draw lines, arcs, text and pins */
if (TEST_FLAG(SELECTEDFLAG, Element))
XSetForeground(Dpy, Output.fgGC, PCB->SelectedColor);
else
XSetForeground(Dpy, Output.fgGC, PCB->ElementColor);
DrawElementPackageLowLevel(Element);
}
/* ---------------------------------------------------------------------------
* draw pins of an element
*/
void DrawElementPins(ElementTypePtr Element)
{
PIN_LOOP(Element, DrawPin(pin););
}
/* ---------------------------------------------------------------------------
* erase a via object
*/
void EraseVia(PinTypePtr Via)
{
XSetForeground(Dpy, Output.fgGC, Settings.bgColor);
DrawPinOrViaLowLevel(Via);
}
/* ---------------------------------------------------------------------------
* erase a pin object
*/
void ErasePin(PinTypePtr Pin)
{
XSetForeground(Dpy, Output.fgGC, Settings.bgColor);
DrawPinOrViaLowLevel(Pin);
}
/* ---------------------------------------------------------------------------
* erases a line on a layer
*/
void EraseLine(LineTypePtr Line)
{
XSetForeground(Dpy, Output.fgGC, Settings.bgColor);
DrawLineLowLevel(Line);
}
/* ---------------------------------------------------------------------------
* erases a text on a layer
*/
void EraseText(TextTypePtr Text)
{
XSetForeground(Dpy, Output.fgGC, Settings.bgColor);
DrawTextLowLevel(Text);
}
/* ---------------------------------------------------------------------------
* erases a polygon on a layer
*/
void ErasePolygon(PolygonTypePtr Polygon)
{
XSetForeground(Dpy, Output.fgGC, Settings.bgColor);
DrawPolygonLowLevel(Polygon);
}
/* ---------------------------------------------------------------------------
* erases an element
*/
void EraseElement(ElementTypePtr Element)
{
/* set color and draw lines, arcs, text and pins */
XSetForeground(Dpy, Output.fgGC, Settings.bgColor);
ELEMENTLINE_LOOP(Element, DrawLineLowLevel(line););
ARC_LOOP(Element, DrawArcLowLevel(arc););
DrawTextLowLevel(&ELEMENT_TEXT(PCB, Element));
PIN_LOOP(Element, DrawPinOrViaLowLevel(pin););
}
/* ---------------------------------------------------------------------------
* erases the name of an element
*/
void EraseElementName(ElementTypePtr Element)
{
XSetForeground(Dpy, Output.fgGC, Settings.bgColor);
DrawTextLowLevel(&ELEMENT_TEXT(PCB, Element));
}
/* ---------------------------------------------------------------------------
* draws grid points if the distance is >= MIN_GRID_DISTANCE
*/
void DrawGrid(void)
{
Position minx, miny,
maxx, maxy,
x, y;
if (TO_SCREEN(PCB->Grid) >= MIN_GRID_DISTANCE)
{
minx = TO_PCB_X(Output.OffsetX);
miny = TO_PCB_Y(Output.OffsetY);;
maxx = TO_PCB_X(Output.OffsetX +Output.Width);
maxy = TO_PCB_Y(Output.OffsetY +Output.Height);
maxx = MIN((Dimension) maxx, PCB->MaxWidth);
maxy = MIN((Dimension) maxy, PCB->MaxHeight);
for (y = miny; y <= maxy; y += PCB->Grid)
for (x = minx; x <= maxx; x += PCB->Grid)
XDrawPoint(Dpy, Output.OutputWindow, Crosshair.AttachGC,
TO_SCREEN_X(GRIDFIT_X(x)), TO_SCREEN_Y(GRIDFIT_Y(y)));
}
}